<?php
/**
 * Spaph_Config
 *
 * Parse Ini config files into objects. This is inspired by Zend Config.
 *
 * $config = Spaph_Config('path/to/conf.ini','Production');
 */
class Spaph_Config
{
    public function __construct($file=null,$loadSection=null)
    {
        if(isset($file)) {
            $config = $this->parse(parse_ini_file($file,true),$loadSection);

            // Convert loaded section of config into objects.
            foreach($this->arr2obj($config) as $prop => $val) {
                $this->$prop = $val;
            }
        }
    }

    public function __get($prop)
    {
        return null;
    }

    /**
     * Parse the result of parse_ini_file. Merge sections like
     * development:production.
     *
     * @param array $config
     * @param string $loadSection
     * @return array
     */
    private function parse($config, $loadSection)
    {
        $merge               = array();
        $load_config_section = null;

        // First populate merge array with one or two sections. Load the config section.
        foreach(array_keys($config) as $section) {
            $merge = explode(':',preg_replace('/\s+/','',$section));

            // Found loadSection in merge array!
            if(in_array($loadSection, $merge)) {
                $load_config_section = $config[$section];
                break;
            }
        }

        // Uh oh
        if(is_null($load_config_section))
            throw new Exception('Cannot find section, '.$loadSection.', in config file.');

        // Need to merge sections.
        if(isset($merge[1]))
            $load_config_section = array_merge($config[$merge[1]], $load_config_section);

        // Convert the dots separating properties into arrays.
        $make_me_an_obj = array();
        foreach($load_config_section as $key => $val) {
            $make_me_an_obj = $this->processKey($make_me_an_obj, $key, $val);
        }

        return $make_me_an_obj;
    }

    /**
     * Convert object properties into array.
     *
     * @return array
     */
    public function toArray()
    {
        $arr = array();
        foreach($this as $prop => $val) {
            if(is_object($val)) {
                $arr[$prop] = $val->toArray();
            }
            else {
                $arr[$prop] = $this->$prop;
            }
        }

        return $arr;
    }

    /**
     * Convert array into an object of object properties. Fortunate to find
     * an example of this on the web.
     *
     * @param  array $data
     * @return object
     */
    private function arr2obj($data)
    {
        if(is_array($data)) {
            $obj = new Spaph_Config();
            $mix = array_map(array($this,__FUNCTION__),$data);
            foreach($mix as $prop => $val) {
                $obj->$prop = $val;
            }
            return $obj;
        }

        return $data;
    }

    /**
     * Break string (key) prop1.prop2.prop3 = 'test' (val) into an array like
     * $arr['prop1']['prop2']['prop3'] = 'test'
     *
     * @param array $arr
     * @param string $key
     * @param mix $val
     * @return array
     */
    private function processKey($arr, $key, $val)
    {
        if (strpos($key, '.') !== false) {
            $pieces = explode('.', $key, 2);
            if(!isset($arr[$pieces[0]])) {
                $arr[$pieces[0]] = array();
            }

            $arr[$pieces[0]] = $this->processKey($arr[$pieces[0]], $pieces[1], $val);
        }
        else {
            $arr[$key] = $val;
        }

        return $arr;
    }
}

